package com.sikaryofficial.system.manager.report;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.sikaryofficial.common.core.constant.CacheConstants;
import com.sikaryofficial.common.core.constant.ReportConstant;
import com.sikaryofficial.common.core.utils.DateUtils;
import com.sikaryofficial.common.redis.service.RedisService;
import com.sikaryofficial.system.domain.SysUserDaily;
import com.sikaryofficial.system.domain.vo.ReportTrendVO;
import com.sikaryofficial.system.service.ISysRegisterDailyService;
import com.sikaryofficial.system.service.ISysUserDailyService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.text.MessageFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * @author : qinjinyuan
 * @desc :
 * @date : 2024/03/02 21:08
 */
@Service
@Slf4j
public class ReportJobManager {
    @Autowired
    private RedisService redisService;
    @Autowired
    private ISysRegisterDailyService registerDailyService;
    @Autowired
    private ISysUserDailyService sysUserDailyService;

    @Value("${hismk.common.zoneId}")
    private String zoneId;

    /**
     * 新增或更新 日活 天数据
     *
     * @return
     */
    public Boolean activityDaily() {
        // 获取昨天及今天的所有redis key
        List<String> allKeys = getAllKeys(CacheConstants.DAY_DETAIL_ACTIVITY_ITEM2_KEY);
        log.info("keys:{}", allKeys);
        // 删除前天的日活缓存数据，清理缓存存储空间
        removeCacheData(CacheConstants.DAY_DETAIL_ACTIVITY_ITEM2_KEY);
        if (CollUtil.isEmpty(allKeys)) {
            return true;
        }
        List<SysUserDaily> insertDataList = Lists.newArrayList();
        for (String catchKey : allKeys) {
            String[] catchKeys = catchKey.split(":");
            Date genDate = null;
            try {
                genDate = DateUtils.parseDate(catchKeys[3], "yyyyMMdd");
            } catch (Exception e) {
                log.error("parseDate error:{}", e);
            }
            Set<String> dataSet = redisService.getCacheSet(catchKey);
            for (String userId : dataSet) {
                SysUserDaily userDaily = new SysUserDaily();
                insertDataList.add(userDaily);
                userDaily.setSubTotal(1L);
                userDaily.setBrand(catchKeys[4]);
                userDaily.setGenDate(genDate);
                userDaily.setObjectId(userId);
                userDaily.setHasLogin(0);
            }
        }
        insertDataList.forEach(item -> sysUserDailyService.saveOrUpdateDaily(
                dearGenDateToLocalDate(item.getGenDate()), item.getBrand(), item.getSubTotal(), item.getObjectId(), item.getHasLogin()));
        return true;
    }

    public Boolean activityDailyNoLogin() {
        // 获取昨天及今天的所有redis key
        List<String> allKeys = getAllKeys(CacheConstants.DAY_DETAIL_NO_LOGIN_ACTIVITY_ITEM2_KEY);
        log.info("keys:{}", allKeys);
        // 删除前天的日活缓存数据，清理缓存存储空间
        removeCacheData(CacheConstants.DAY_DETAIL_NO_LOGIN_ACTIVITY_ITEM2_KEY);
        if (CollUtil.isEmpty(allKeys)) {
            return true;
        }
        List<SysUserDaily> insertDataList = Lists.newArrayList();
        for (String catchKey : allKeys) {
            String[] catchKeys = catchKey.split(":");
            Date genDate = null;
            try {
                genDate = DateUtils.parseDate(catchKeys[3], "yyyyMMdd");
            } catch (Exception e) {
                log.error("parseDate error:{}", e);
            }
            Set<String> dataSet = redisService.getCacheSet(catchKey);
            for(String ipAddress  : dataSet){
                SysUserDaily userDaily = new SysUserDaily();
                insertDataList.add(userDaily);
                userDaily.setSubTotal(1L);
                userDaily.setBrand(catchKeys[4]);
                userDaily.setGenDate(genDate);
                userDaily.setObjectId(ipAddress);
                userDaily.setHasLogin(1);
            }
        }
        insertDataList.forEach(item -> sysUserDailyService.saveOrUpdateDaily(
                dearGenDateToLocalDate(item.getGenDate()), item.getBrand(), item.getSubTotal(), item.getObjectId(), item.getHasLogin()));
        return true;
    }

    private List<String> getAllKeys(String dataSourceCacheKey) {
        List<String> allKeys = Lists.newArrayList();
        // 获取当前日期前一天的日期 (昨天)
        LocalDate yesterday = LocalDate.now().minusDays(1);
        // 定义日期格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        collectRedisKey(dataSourceCacheKey,allKeys, yesterday, formatter);
        // 今天
        LocalDate today = LocalDate.now();
        collectRedisKey(dataSourceCacheKey,allKeys, today, formatter);
        return allKeys;
    }

    private void collectRedisKey(String dataSourceCacheKey,List<String> allKeys, LocalDate yesterday, DateTimeFormatter formatter) {
        // 格式化昨天的日期为字符串
        String yesterdayFormatted = yesterday.format(formatter);
        String cacheKey = MessageFormat.format(dataSourceCacheKey, yesterdayFormatted);
        // 获取昨天的 key集合
        Collection<String> keys = redisService.keys(cacheKey + "*");
        if (CollUtil.isNotEmpty(keys)) {
            allKeys.addAll(keys);
        }
    }

    private void removeCacheData(String dataSourceCacheKey) {
        // 删除前天的缓存数据 ： 因为这个数据结构比较好内存
        LocalDate yesterday = LocalDate.now().minusDays(3);
        // 定义日期格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        // 格式化昨天的日期为字符串
        String yesterdayFormatted = yesterday.format(formatter);
        String cacheKey = MessageFormat.format(dataSourceCacheKey, yesterdayFormatted);
        // 获取昨天的 key集合
        Collection<String> keys = redisService.keys(cacheKey + "*");
        if (CollUtil.isNotEmpty(keys)) {
            log.info("remove hismk:dayDetail:activity: {}", keys);
            redisService.deleteObject(keys);
        } else {
            log.info("remove key is empty");
        }
    }

    public Boolean registerByType(String timeType) {
        Date startDate;
        Date endDate = new Date();
        List<ReportTrendVO> list;
        // 获取当前日期
        LocalDate today = LocalDate.now(ZoneId.of(zoneId));
        switch (timeType) {
            case ReportConstant.DAY_TYPE:
                // 获取昨天的日期
                LocalDate preDay = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).minusDays(1);
                // 将 lastMonday 转换为 java.util.Date
                startDate = Date.from(preDay.atStartOfDay(ZoneId.of(zoneId)).toInstant());
                list = registerDailyService.queryDaily(startDate, endDate);
                list.forEach(item -> registerDailyService.saveOrUpdateDaily(dearGenDateToLocalDate(item.getGenDate()), item.getSubTotal(),item.getUserId()));
                break;
            case ReportConstant.WEEK_TYPE:
                // 获取上周周一的日期
                LocalDate lastMonday = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).minusWeeks(1);
                // 将 lastMonday 转换为 java.util.Date
                startDate = Date.from(lastMonday.atStartOfDay(ZoneId.of(zoneId)).toInstant());
                list = registerDailyService.queryWeekly(startDate, endDate);
                list.forEach(item -> registerDailyService.saveOrUpdateWeekly(item.getWeekNum(), item.getSubTotal()));
                break;
            case ReportConstant.MONTH_TYPE:
                // 获取上个月的第一天
                LocalDate firstDayOfLastMonth = today.with(TemporalAdjusters.firstDayOfMonth()).minusMonths(1);
                startDate = Date.from(firstDayOfLastMonth.atStartOfDay(ZoneId.of(zoneId)).toInstant());
                list = registerDailyService.queryMonthly(startDate, endDate);
                list.forEach(item -> registerDailyService.saveOrUpdateMonthly(dearGenDateToLocalDate(item.getGenDate()), item.getSubTotal())
                );
                break;
            case ReportConstant.QUARTER_TYPE:
                // 今年的第1天
                LocalDate firstDayQuarter = today.with(TemporalAdjusters.firstDayOfYear()).minusMonths(0);
                startDate = Date.from(firstDayQuarter.atStartOfDay(ZoneId.of(zoneId)).toInstant());
                list = registerDailyService.queryQuarterly(startDate, endDate);
                list.forEach(item -> registerDailyService.saveOrUpdateQuarterly(item.getQuarterNum(), item.getSubTotal()));
                break;
            case ReportConstant.YEAR_TYPE:
                // 今年的第1天
                LocalDate firstDayOfLastYear = today.with(TemporalAdjusters.firstDayOfYear()).minusMonths(0);
                startDate = Date.from(firstDayOfLastYear.atStartOfDay(ZoneId.of(zoneId)).toInstant());
                list = registerDailyService.queryYearly(startDate, endDate);
                list.forEach(item -> registerDailyService.saveOrUpdateYearly(dearGenDateToLocalDate(item.getGenDate()), item.getSubTotal()));
                break;
            default:
                log.error("timeType error:{}", timeType);
                break;
        }
        return true;
    }

    private Date dearGenDateToLocalDate(Date genDate) {
        LocalDateTime localDateTime = LocalDateTimeUtil.of(genDate);
        // TODO: 操作系统 设置UTC ;  数据设置为 GMT+0 ; 此处设置为 UTC
        ZonedDateTime utcDateTime = localDateTime.atZone(ZoneId.of(zoneId));
        // 将 UTC 时区的 ZonedDateTime 转换为 Date
        return Date.from(utcDateTime.toInstant());
    }

    public Boolean activityByType(String timeType) {
        Date startDate;
        Date endDate = new Date();
        List<ReportTrendVO> list;
        // 获取当前日期
        LocalDate today = LocalDate.now();
        switch (timeType) {
            case ReportConstant.DAY_TYPE:
                this.activityDaily();
                this.activityDailyNoLogin();
                break;
            case ReportConstant.WEEK_TYPE:
                // 获取上周周一的日期
                LocalDate lastMonday = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).minusWeeks(1);
                // 将 lastMonday 转换为 java.util.Date
                startDate = Date.from(lastMonday.atStartOfDay(ZoneId.of(zoneId)).toInstant());
                list = sysUserDailyService.queryWeekly(startDate, endDate);
                list.forEach(item -> sysUserDailyService.saveOrUpdateWeekly(item.getWeekNum(), item.getBrand(), item.getSubTotal(), item.getHasLogin()));
                break;
            case ReportConstant.MONTH_TYPE:
                // 获取上个月的第一天
                LocalDate firstDayOfLastMonth = today.with(TemporalAdjusters.firstDayOfMonth()).minusMonths(1);
                startDate = Date.from(firstDayOfLastMonth.atStartOfDay(ZoneId.of(zoneId)).toInstant());
                list = sysUserDailyService.queryMonthly(startDate, endDate);
                list.forEach(item -> sysUserDailyService.saveOrUpdateMonthly(dearGenDateToLocalDate(item.getGenDate()), item.getBrand(), item.getSubTotal(), item.getHasLogin()));
                break;
            case ReportConstant.QUARTER_TYPE:
                // 今年的第1天
                LocalDate firstDayQuarter = today.with(TemporalAdjusters.firstDayOfYear()).minusMonths(0);
                startDate = Date.from(firstDayQuarter.atStartOfDay(ZoneId.of(zoneId)).toInstant());
                list = sysUserDailyService.queryQuarterly(startDate, endDate);
                list.forEach(item -> sysUserDailyService.saveOrUpdateQuarterly(item.getQuarterNum(), item.getBrand(), item.getSubTotal(), item.getHasLogin()));
                break;
            case ReportConstant.YEAR_TYPE:
                // 今年的第1天
                LocalDate firstDayOfLastYear = today.with(TemporalAdjusters.firstDayOfYear()).minusMonths(0);
                startDate = Date.from(firstDayOfLastYear.atStartOfDay(ZoneId.of(zoneId)).toInstant());
                list = sysUserDailyService.queryYearly(startDate, endDate);
                list.forEach(item -> sysUserDailyService.saveOrUpdateYearly(dearGenDateToLocalDate(item.getGenDate()), item.getBrand(), item.getSubTotal(), item.getHasLogin()));
                break;
            default:
                log.error("timeType error:{}", timeType);
                break;
        }
        return true;
    }
}
